#include <event2/event.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>

static struct event_base *p_ev_base = NULL;
static int right_answer = -1;
static int remain_question_number = 5;

static struct event *p_30sec_event = NULL;
static struct event *p_20sec_event = NULL;
static struct event *p_10sec_event = NULL;
static struct event *p_stdin_read_event = NULL;

static void AskQuestion();
static void On30SecCallback(int fd, short event, void *arg);
static void On20SecCallback(int fd, short event, void *arg);
static void On10SecCallback(int fd, short event, void *arg);
static void OnStdinReadCallback(int fd, short event, void *arg);

void Game_Init(struct event_base *p_ev_base_)
{
    p_ev_base = p_ev_base_;
    p_30sec_event = evtimer_new(p_ev_base, On30SecCallback, NULL);
    p_20sec_event = evtimer_new(p_ev_base, On20SecCallback, NULL);
    p_10sec_event = evtimer_new(p_ev_base, On10SecCallback, NULL);
    p_stdin_read_event = event_new(p_ev_base, STDIN_FILENO, EV_READ | EV_PERSIST, OnStdinReadCallback, NULL);

    puts("Welcome to Calculate Gate.");
    puts("You need answer 5 questions in 30 seconds. Each question has only 10 second.");
    puts("Here we go!");

    srand(time(NULL));
    struct timeval to = { .tv_sec = 30 };
    event_add(p_30sec_event, &to);
    to.tv_sec = 20;
    event_add(p_20sec_event, &to);
    event_add(p_stdin_read_event, NULL);

    AskQuestion();
}

void Game_Cleanup()
{
    event_del(p_30sec_event);
    event_del(p_20sec_event);
    event_del(p_10sec_event);
    event_del(p_stdin_read_event);

    event_free(p_30sec_event);
    event_free(p_20sec_event);
    event_free(p_10sec_event);
    event_free(p_stdin_read_event);
}

static void AskQuestion()
{
    event_del(p_10sec_event);

    int a = random() % 100;
    int b = random() % 100;
    right_answer = a + b;
    printf("%d + %d = ? \nyour answer: ", a, b);
    fflush(stdout);

    --remain_question_number;
    struct timeval to = { .tv_sec = 10 };
    event_add(p_10sec_event, &to);
}

static void On30SecCallback(int fd, short event, void *arg)
{
    puts("\ntime is up, you fail!");
    event_base_loopexit(p_ev_base, NULL);
}

static void On20SecCallback(int fd, short event, void *arg)
{
    puts("\n10 sec remain...");
}

static void On10SecCallback(int fd, short event, void *arg)
{
    puts("\ntimeout. You fail!");
    event_base_loopexit(p_ev_base, NULL);
}

static void OnStdinReadCallback(int fd, short event, void *arg)
{
    char input_buff[200];
    int rsize = read(STDIN_FILENO, input_buff, sizeof(input_buff));
    input_buff[rsize - 1];

    int answer = atoi(input_buff);
    if (answer == right_answer) {
        if (remain_question_number == 0) {
            puts("Congratulation! You win.");
            event_base_loopexit(p_ev_base, NULL);
        } else {
            AskQuestion();
        }
    } else {
        puts("wrong answer. You fail.");
        event_base_loopexit(p_ev_base, NULL);
    }
}
